package com.tang.excel.batch.export;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author: tang
 * @Description:
 * @Date 2025/1/2 14:49
 */
@Slf4j
@Service
public class ExportService {

    @Resource
    PandaMapper pandaMapper;

    /**
     * 单次批处理任务大小
     */
    private final static Integer PAGE_SIZE = 10 * 10000;

    /**
     * 提交导出任务的线程
     */
    private static final ThreadPoolExecutor SUBMIT_EXPORT_THREAD_POOL =
            new ThreadPoolExecutor(5, 10, 1,
                    TimeUnit.SECONDS, new ArrayBlockingQueue<>(5));

    /**
     * 读/写操作的线程
     */
    private static final ThreadPoolExecutor EXPORT_THREAD_POOL =
            new ThreadPoolExecutor(5, 10, 1,
                    TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));

    class ExportTask implements Runnable {

        /**
         * 单任务锁
         */
        private final Object lock = new Object();

        @Override
        public void run() {

            StopWatch stopWatch = new StopWatch();
            stopWatch.start();

            log.info("开始导入任务...");
            Integer count = ExportService.this.pandaMapper.selectCount();

            int pageCount = (int) Math.ceil((double) count / PAGE_SIZE);

            log.info("待处理总批次数:{}...",pageCount);

            ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
            excelWriterBuilder.excelType(ExcelTypeEnum.CSV);
            excelWriterBuilder.file("/Users/tanglonglong/Downloads/test"+ Instant.now() +".cvs");
            WriteSheet writeSheet = new WriteSheet();
            ExcelWriter excelWriter = excelWriterBuilder.build();

            CountDownLatch countDownLatch = new CountDownLatch(pageCount);
            for (int i = 0; i < pageCount; i++) {
                int finalI = i;
                EXPORT_THREAD_POOL.execute(() -> {
                    try {
                        log.info("第"+finalI+"批开始写入...");
                        List<Panda> pandaList = pandaMapper.selectPage(finalI * PAGE_SIZE, PAGE_SIZE);
                        if (CollectionUtils.isEmpty(pandaList)) {
                            return;
                        }

                        // easy excel 不支持 多线程写入，同一个任务请求，公用一把锁
                        synchronized (lock) {
                            excelWriter.write(pandaList, writeSheet);
                            log.info("第"+finalI+"批写入成功...");
                        }

                    }finally {
                        countDownLatch.countDown();
                    }
                });
            }

            try {
                log.info("等待线程任务写入完成...");
                countDownLatch.await();
                stopWatch.stop();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("线程任务写入完成!!!,任务耗时:{}s",stopWatch.getTotalTimeSeconds());
            excelWriter.close();

            // 文件上传到OSS
        }

    }

    public void exportData(ExportDTO exportDTO,HttpServletResponse response) {
        if (SUBMIT_EXPORT_THREAD_POOL.getQueue().remainingCapacity() == 0) {
            throw new RuntimeException("队列任务已满！请等待其他任务完成!");
        }
        SUBMIT_EXPORT_THREAD_POOL.execute(new ExportTask());
    }

}
